package com.example.everying.service.user.impl;/*
 * 项目名称: everything
 * 文件名: WxLoginServiceImpl
 * 作者: 张泽阳
 * 日期: 2025/5/14
 * 描述:
 */

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.everying.constant.CacheConstants;
import com.example.everying.constant.PointsConstant;
import com.example.everying.context.UserContext;
import com.example.everying.mapper.user.UserBindRelMapper;
import com.example.everying.model.dto.user.AppWxLoginDto;
import com.example.everying.model.dto.user.WxLoginDto;
import com.example.everying.model.dto.user.WxRegisterDto;
import com.example.everying.model.entity.invite.InviteCodeEntity;
import com.example.everying.model.entity.user.*;
import com.example.everying.model.vo.user.LoginUser;
import com.example.everying.model.vo.user.ResolvePhoneVO;
import com.example.everying.model.vo.user.UserInfoVo;
import com.example.everying.model.vo.user.WxLoginVo;
import com.example.everying.service.user.*;
import com.example.everying.utils.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;

@Slf4j
@Service
public class WxLoginServiceImpl implements WxLoginService {

    @Value("${aliyun.oss.urlPrefix}")
    private String urlPrefix;
    @Autowired
    private WxCoreUtil wxCoreUtil;
    @Autowired
    private UserService userService;
    @Autowired
    private QueryLocationUtil queryLocationUtil;

    @Autowired
    private InviteCodeService inviteCodeService;

    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private UserBalanceService userBalanceService;

    @Autowired
    private UserScoreService userScoreService;

    @Autowired
    private UserBindRelService userBindRelService;

    @Autowired
    private PointsAccountService pointsAccountService;
    @Autowired
    private ActivityPointsConfigService activityPointsConfigService;


    @Override
    public Result<?> login(WxLoginDto wxLoginDto, HttpServletRequest request) {
        // 账号密码登录
        if (wxLoginDto.getType() != null && wxLoginDto.getType().equals("1")) {
            List<UserEntity> userList = userService.getUserByPhone(wxLoginDto.getPhone());
            UserEntity userByPhone = userList.size() > 0 ? userList.get(0) : null;
            WxLoginVo wxLoginVo = new WxLoginVo();

            if (!isValidChinesePhoneNumber(wxLoginDto.getPhone())) {
                return Result.fail("手机号格式错误");
            }

            if (userByPhone == null) {
                // 账号不存在-》注册
                return Result.fail("账号不存在,请去注册账号");
            }
            if (userByPhone.getIsDelete().equals(1)) {
                return Result.fail("账号已注销");
            }
            if (userByPhone.getPassword() == null) {
                return Result.fail("密码不存在，请先设置密码");
            }
            if (!PaymentPasswordUtil.verify(wxLoginDto.getPassword(), userByPhone.getPassword())) {
                return Result.fail("密码错误");
            }


            ResolvePhoneVO resolvePhoneVO = wxCoreUtil.getOpenId(wxLoginDto.getCode());
            if (resolvePhoneVO.getOpenId() == null) {
                System.out.println("openId为空");

//                return Result.fail("未找到微信用户");
            }
            if (userByPhone.getOpenId() != null) {
                wxLoginVo.setOpenId(resolvePhoneVO.getOpenId());
                userByPhone.setOpenId(resolvePhoneVO.getOpenId());
            }
//            userByPhone.setIsFirst(userByPhone.getIsFirst() == null ? 1 : userByPhone.getIsFirst() + 1);
//            userByPhone.setPopupClosed(false);

            userService.updateById(userByPhone);
            String token = JwtUtils.sign(userByPhone.getId());
            saveTokenHash(userByPhone.getId(), token);
            wxLoginVo.setToken(token);
            return Result.ok(wxLoginVo);
        }

        // 微信登录


        WxLoginVo wxLoginVo = new WxLoginVo();
        ResolvePhoneVO resolvePhoneVO = wxCoreUtil.getOpenId(wxLoginDto.getCode());

        if (resolvePhoneVO.getOpenId() == null || resolvePhoneVO.getOpenId().isEmpty()) {
            System.out.println("openId为空");
            log.info("openId为空");
            return Result.fail("未找到微信用户");
        }
        wxLoginVo.setOpenId(resolvePhoneVO.getOpenId());
        resolvePhoneVO.setIv(wxLoginDto.getIv());
        resolvePhoneVO.setEncryptedData(wxLoginDto.getEncryptedData());
        // 解析小程序用户手机号
        WeChatPhoneNumberDecryptor weChatPhoneNumberDecryptor = new WeChatPhoneNumberDecryptor();
        try {

            log.info("encrypteData:{}", resolvePhoneVO.getEncryptedData());
            log.info("sessionKey:{}", resolvePhoneVO.getSessionKey());
            log.info("iv:{}", resolvePhoneVO.getIv());
            String phoneObject = WeChatPhoneNumberDecryptor.decrypt(resolvePhoneVO.getEncryptedData(), resolvePhoneVO.getSessionKey(), resolvePhoneVO.getIv());
            JSONObject obj = JSONObject.parseObject(phoneObject);
            String phoneNumber = obj.getString("phoneNumber");
            if (phoneNumber == null) {
                return Result.fail("获取手机号失败");
            }
            wxLoginVo.setPhone(phoneNumber);

        } catch (Exception e) {
            e.printStackTrace();
            return Result.fail("获取手机号失败");
        }


//        wxLoginVo.setOpenId("oJWoj59qYLBafzyD4Z0AGefkTnmo00012");
//        UserEntity user = userService.getUserByOpenId(wxLoginVo.getOpenId());
        // 根据手机号获取用户
        List<UserEntity> userList = userService.getUserByPhone(wxLoginVo.getPhone());
        UserEntity user = userList.size() > 0 ? userList.get(0) : null;
        if (user != null) {
            user.setLocation(queryLocationUtil.queryLocation(IpUtils.getClientIp(request)));
            user.setOpenId(wxLoginVo.getOpenId());
            userService.updateById(user);
        }


        if (user == null || user.getIsDelete().equals(1)) {
//            Random random = new Random();
//            String imageName = String.valueOf((random.nextInt(5) + 1));
//            String avatarUrl = urlPrefix + "/avatar/" + imageName + ".png";
//            user = new UserEntity();
//            user.setOpenId(wxLoginVo.getOpenId());
//            user.setPhone(wxLoginVo.getPhone());
//            user.setId(RandomUtil.generateId());
//            user.setUserName("事包用户" + RandomUtil.generateName());
//            user.setIsAdministrator(2);
//            user.setSignTime(LocalDateTime.now());
//            user.setState(1);
//            user.setIsDelete(0);
//            user.setCreateTime(LocalDateTime.now());
//            user.setUpdateTime(LocalDateTime.now());
//            user.setAvatarUrl(avatarUrl);
//            user.setLocation(queryLocationUtil.queryLocation(IpUtils.getClientIp(request)));
//
//            wxLoginVo.setUsername(user.getUserName());
//            // 生成邀请码
//            InviteCodeEntity inviteCode = new InviteCodeEntity();
//            inviteCode.setId(RandomUtil.generateId());
//            inviteCode.setInviteCode(InviteCodeUtil.idToCode(Long.parseLong(user.getId())));
//            inviteCode.setOwnerId(user.getId());
//            inviteCode.setCreateTime(LocalDateTime.now());
//            inviteCodeService.save(inviteCode);
//            user.setInviteCode(inviteCode.getInviteCode());
//            int isInsert = userService.insertUser(user);
            UserEntity register = register(wxLoginVo.getPhone(), null, wxLoginVo.getOpenId());

            wxLoginVo.setOpenId(register.getOpenId());

            String token = JwtUtils.sign(register.getId());
            saveTokenHash(register.getId(), token);
            wxLoginVo.setToken(token);
            return Result.ok(wxLoginVo);
//            if (register != null) {
//                // 初始化余额
//                saveUserBalance(user);
//            }

            // todo 现存用户在用户评分表中没有数据 登录是插入新数据
            // 添加用户评分记录
//            addUserScore(user.getId());

            // 添加用户评分记录
//            UserScore userScore = new UserScore();
//            userScore.setUserId(user.getId());
//            userScore.setCreateTime(LocalDateTime.now());
//            userScore.setUpdateTime(LocalDateTime.now());
//            userScoreService.save(userScore);
        }

//        if (!user.getPhone().equals(wxLoginVo.getPhone())){
//            return Result.fail("请使用此微信登录时绑定的手机号登录");
//        }


        if (user != null) {
            wxLoginVo.setOpenId(user.getOpenId());

            String token = JwtUtils.sign(user.getId());
            saveTokenHash(user.getId(), token);
            wxLoginVo.setToken(token);
        }


        return Result.ok(wxLoginVo);
    }

    @Override
    public Result<?> appLogin(AppWxLoginDto appWxLoginDto) {
        UserBindRel userBindRel = userBindRelService.getByUnionId(appWxLoginDto.getUnionid());
        if (userBindRel == null) {
            // 绑定微信
            return Result.ok(0);
        }
        UserInfoVo userById = userService.getUserById(userBindRel.getUserId());
        if (userById.getIsDelete() == 1) {
            return Result.ok("0");
        }
        String token = JwtUtils.sign(userById.getId());
        WxLoginVo wxLoginVo = new WxLoginVo();
        wxLoginVo.setOpenId(appWxLoginDto.getOpenid());
        wxLoginVo.setPhone(userById.getPhone());
        wxLoginVo.setAvatarUrl(userById.getAvatarUrl());
        wxLoginVo.setUsername(userById.getUserName());
        wxLoginVo.setToken(token);
        saveTokenHash(userById.getId(), token);

        return Result.ok(wxLoginVo);
    }


    /**
     * 验证token是否失效
     *
     * @param request 请求对象，用于获取请求头
     * @return boolean
     */
    @Override
    public boolean validateToken(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        String userId = JwtUtils.tokenParse(token);
        if (userId.isEmpty()) {
            return false;
        }
        // 统计用户日活，重复的不计算
        redisUtils.recordDAU(userId);
        log.info("日期：{} -> 人数：{}", LocalDate.now(), redisUtils.getDAUCount(LocalDate.now()));
        // 验证redis的token
        return validateAndRenew(userId, token);
//        return false;
    }

    /**
     * @return boolean
     */
    @Override
    public boolean logout() {
        UserInfoVo userInfoVo = UserContext.getUser();
        if (userInfoVo == null) {
            return true;
        }
        log.info("用户{}退出登录", userInfoVo.getPhone());
        String keys = getTokenKey(userInfoVo.getId());
        redisUtils.deleteObject(Collections.singleton(keys));
        UserContext.clear();
        return true;
    }

    /**
     * 注销账号 目前只逻辑删除了用户信息
     *
     * @param id 用户ID
     * @return 是否取消成功
     */
    @Override
    @Transactional
    public Boolean cancelAccount(String id) {
        UserEntity user = userService.getById(id);
        user.setIsDelete(1);
        boolean flag = userService.updateById(user);
        userBindRelService.deleteByUserId(id);
        String keys = getTokenKey(id);
        redisUtils.deleteObject(Collections.singleton(keys));
        UserContext.clear();
        return flag;
    }

    /**
     * 异步保存用户余额信息
     * <p>
     * 本方法通过异步方式初始化并保存用户余额记录，旨在提高系统响应速度和性能
     * 主要功能包括：
     * 1. 创建UserBalanceEntity实例，设置用户ID、可用余额、最后余额以及创建和更新时间
     * 2. 调用userBalanceService的save方法保存用户余额实体到数据库
     *
     * @param user UserEntity类型的用户实体，包含用户的基本信息，用于获取用户ID
     */
    @Async
    protected void saveUserBalance(UserEntity user) {
        // 初始化用户余额实体
        UserBalanceEntity userBalanceEntity = new UserBalanceEntity();
        userBalanceEntity.setUserId(user.getId());
        userBalanceEntity.setAvailableAmount(BigDecimal.ZERO);
        userBalanceEntity.setLastAmount(BigDecimal.ZERO);
        userBalanceEntity.setVersion(0);
        userBalanceEntity.setCreateTime(LocalDateTime.now());
        userBalanceEntity.setUpdateTime(LocalDateTime.now());

        // 保存用户余额实体到数据库
        userBalanceService.save(userBalanceEntity);
    }

    /**
     * 根据用户ID生成缓存中的Token键名
     *
     * @param userId 用户ID，用于生成唯一的Token键名
     * @return 返回生成的Token键名
     */
    private String getTokenKey(String userId) {
        return CacheConstants.LOGIN_TOKEN_KEY + userId;
    }


    //    /**
//     * 存储或更新Token（7天有效期）
//     *
//     * @param userId 用户标识
//     * @param token  令牌字符串
//     */
    @Override
    public void saveTokenHash(String userId, String token) {
        String key = getTokenKey(userId);

        // 计算过期时间（当前时间+指定小时数）
        long expireTimestamp = System.currentTimeMillis() / 1000 + 7 * 24 * 3600;
        UserInfoVo userInfoVo = userService.getUserById(userId);
        LoginUser loginUser = new LoginUser();
        loginUser.setToken(token);
        loginUser.setExpire(String.valueOf(expireTimestamp));
        BeanUtil.copyProperties(userInfoVo, loginUser);

        // 存储并设置TTL
        redisUtils.setCacheObject(key, loginUser);
        if (userId.equals("451625061011310001")) {
            return;
        }
        redisUtils.expire(key, CacheConstants.EXPIRE_DAYS, TimeUnit.DAYS);
    }


    /**
     * 手机号密码注册
     *
     * @param wxRegisterDto
     * @return
     */
    @Override
    public Result<?> registerByPhone(WxRegisterDto wxRegisterDto) {
        if (!isValidChinesePhoneNumber(wxRegisterDto.getPhone())) {
            return Result.fail("手机号格式错误");
        }
        String key = CacheConstants.SMS_CODE + wxRegisterDto.getPhone() + ":" + wxRegisterDto.getCode();
        String code = redisUtils.getCacheObject(key);
        if (code == null || !code.equals(wxRegisterDto.getCode())) {
            return Result.fail("验证码错误或已过期");
        }

        List<UserEntity> userByPhoneList = userService.getUserByPhone(wxRegisterDto.getPhone());
        UserEntity userByPhone = userByPhoneList.size() > 0 ? userByPhoneList.get(0) : null;
        if (userByPhone != null && userByPhone.getIsDelete() == 0) {
            return Result.fail("手机号已注册");
        }

        if (!isValidPassword(wxRegisterDto.getFirstPassword())) {
            return Result.fail("密码格式错误");
        }
        if (!wxRegisterDto.getFirstPassword().equals(wxRegisterDto.getSecondPassword())) {
            return Result.fail("两次密码不一致");
        }
//        UserEntity user = new UserEntity();
//        Random random = new Random();
//        String imageName = String.valueOf((random.nextInt(5) + 1));
//        String avatarUrl = urlPrefix + "/avatar/" + imageName + ".png";
//        user.setAvatarUrl(avatarUrl);
//        user.setId(RandomUtil.generateId());
//        user.setPassword(PaymentPasswordUtil.encrypt(wxRegisterDto.getFirstPassword()));
//        user.setPhone(wxRegisterDto.getPhone());
//        user.setSignTime(LocalDateTime.now());
////        user.setUserName(wxRegisterDto.getPhone());
//        user.setUserName("事包用户" + RandomUtil.generateName());
//        user.setIsAdministrator(2);
//        user.setCreditValue(5.0);
//        user.setBalance(BigDecimal.ZERO);
//        user.setState(1);
//        user.setUpdateTime(LocalDateTime.now());
//        user.setCreateTime(LocalDateTime.now());
//
//        // 生成邀请码
//        InviteCodeEntity inviteCode = new InviteCodeEntity();
//        inviteCode.setId(RandomUtil.generateId());
//        inviteCode.setInviteCode(InviteCodeUtil.idToCode(Long.parseLong(user.getId())));
//        inviteCode.setOwnerId(user.getId());
//        inviteCode.setCreateTime(LocalDateTime.now());
//        inviteCodeService.save(inviteCode);
//        user.setInviteCode(inviteCode.getInviteCode());
//        boolean save = userService.save(user);
        UserEntity user = register(wxRegisterDto.getPhone(), wxRegisterDto.getFirstPassword(), null);
        if (user != null) {
            return Result.ok("注册成功");
        }
        return Result.fail("注册失败");
    }

    @Override
    public Result<?> updatePassword(WxRegisterDto wxRegisterDto) {
        if (!isValidChinesePhoneNumber(wxRegisterDto.getPhone())) {
            return Result.fail("手机号格式错误");
        }
        String key = CacheConstants.SMS_CODE + wxRegisterDto.getPhone() + ":" + wxRegisterDto.getCode();
        String code = redisUtils.getCacheObject(key);
        List<UserEntity> userByPhoneList = userService.getUserByPhone(wxRegisterDto.getPhone());
        UserEntity userByPhone = userByPhoneList.size() > 0 ? userByPhoneList.get(0) : null;
        if (userByPhone.getIsDelete() == 1) {
            return Result.fail("用户已注销");
        }
        if (code == null || !code.equals(wxRegisterDto.getCode())) {
            return Result.fail("验证码错误或已过期");
        }
        if (!isValidPassword(wxRegisterDto.getFirstPassword())) {
            return Result.fail("密码格式错误");
        }
        if (!wxRegisterDto.getFirstPassword().equals(wxRegisterDto.getSecondPassword())) {
            return Result.fail("两次密码不一致");
        }
//        List<UserEntity> userByPhoneList = userService.getUserByPhone(wxRegisterDto.getPhone());
//        UserEntity userByPhone = userByPhoneList.size() > 0 ? userByPhoneList.get(0) : null;
        if (userByPhone == null) {
            return Result.fail("用户不存在");
        }
        userByPhone.setPassword(PaymentPasswordUtil.encrypt(wxRegisterDto.getFirstPassword()));
        userByPhone.setUpdateTime(LocalDateTime.now());
        boolean update = userService.updateById(userByPhone);
        if (update) {
            return Result.ok("修改密码成功");
        }

        return Result.fail("修改密码失败");
    }


    /**
     * 验证并续期Token(暂时不续期，直接让用户重新登录)
     */
    public boolean validateAndRenew(String userId, String clientToken) {
        String key = getTokenKey(userId);
        LoginUser loginUser = redisUtils.getCacheObject(key);

        // 验证逻辑
        return loginUser != null &&
                clientToken.equals(loginUser.getToken()) &&
                Long.parseLong(loginUser.getExpire()) >= System.currentTimeMillis() / 1000;

        // 续期（复用saveToken方法）
//        this.saveTokenHash(userId, clientToken);
    }


    public void addUserScore(String id) {
        LambdaQueryWrapper<UserScore> scoreQueryWrapper = new LambdaQueryWrapper<>();
        scoreQueryWrapper.eq(UserScore::getUserId, id);
        if (userScoreService.getBaseMapper().selectCount(scoreQueryWrapper) == 0) {
            UserScore userScore = new UserScore();
            userScore.setUserId(id);
            userScore.setCreditWeight(0.0);
            userScore.setLastCreditUpdateMonth(LocalDateTime.now().getMonth().getValue());
            userScore.setCreateTime(LocalDateTime.now());
            userScore.setUpdateTime(LocalDateTime.now());
            userScoreService.save(userScore);
        }
    }

    /**
     * 校验手机号是否合法
     *
     * @param phoneNumber 待校验的手机号
     * @return true-合法 false-不合法
     */
    public static boolean isValidChinesePhoneNumber(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
            return false;
        }

        // 正则表达式匹配中国大陆手机号
        // 1. 以1开头
        // 2. 第二位是3-9的数字
        // 3. 总共11位数字
        String regex = "^1[3-9]\\d{9}$";
        return Pattern.matches(regex, phoneNumber);
    }

    /**
     * 校验密码长度是否为6-16位
     *
     * @param password 待校验的密码
     * @return true-合法 false-不合法
     */
    public static boolean isValidPassword(String password) {
        if (password == null) {
            return false;
        }
        // 正则匹配：6-16位任意字符（包括特殊字符）
        String regex = "^.{6,16}$";
        return Pattern.matches(regex, password);
    }

    @Transactional
    public UserEntity register(String phone, String password, String openid) {
        Long registerCount  = userService.getRegisterCount(phone);

        UserEntity user = new UserEntity();
//        if (registerCount > 0) {
//            user.setIsFirst(Math.toIntExact(registerCount));
//        }
        user.setIsFirst(Math.toIntExact(registerCount));
        Random random = new Random();
        String imageName = String.valueOf((random.nextInt(5) + 1));
        String avatarUrl = urlPrefix + "/avatar/" + imageName + ".png";
        user.setAvatarUrl(avatarUrl);
        user.setId(RandomUtil.generateId());
        if (password != null) {
            user.setPassword(PaymentPasswordUtil.encrypt(password));
        }
        if (openid != null) {
            user.setOpenId(openid);
        }
        user.setPhone(phone);
        user.setSignTime(LocalDateTime.now());
//        user.setUserName(wxRegisterDto.getPhone());
        user.setUserName("事包用户" + RandomUtil.generateName());
        user.setIsAdministrator(2);
        user.setCreditValue(5.0);
        user.setBalance(BigDecimal.ZERO);
        user.setState(1);
//        user.setIsFirst(1);
        user.setPopupClosed(false);
        user.setUpdateTime(LocalDateTime.now());
        user.setCreateTime(LocalDateTime.now());

        // 生成邀请码
        InviteCodeEntity inviteCode = new InviteCodeEntity();
        inviteCode.setId(RandomUtil.generateId());
        inviteCode.setInviteCode(InviteCodeUtil.idToCode(Long.parseLong(user.getId())));
        inviteCode.setOwnerId(user.getId());
        inviteCode.setCreateTime(LocalDateTime.now());
        inviteCodeService.save(inviteCode);
        user.setInviteCode(inviteCode.getInviteCode());
        boolean save = userService.save(user);
        if (save) {
            // 添加用户余额
            saveUserBalance(user);
            addUserScore(user.getId());
            addUserPoints(user.getId(), user.getIsFirst());

        }
        return user;
    }

    /**
     * 为用户添加积分的方法
     *
     * @param id 用户ID
     */
    private void addUserPoints(String id,Integer isFirst) {
        // 按活动添加积分
        // 获取用户注册类型的积分配置
        ActivityPointsConfig activityPointsConfig = activityPointsConfigService.getRewardConfigByType(PointsConstant.USER_REGISTER_POINTS);
        boolean isActivity = false;
        int points = 0;
        // 判断是否存在有效的积分活动配置
        if (activityPointsConfig != null) {
            // 根据配置ID检查活动是否有效
            isActivity = activityPointsConfigService.checkActivityConfigById(activityPointsConfig.getId());
        }
        // 如果活动有效，则执行积分添加操作
        if (isActivity) {
            points = activityPointsConfig.getPoints();
        }
        // 创建积分账户对象
        PointsAccount pointsAccount = new PointsAccount();
        // 设置用户ID
        pointsAccount.setUserId(id);
        // 设置总积分数量
        pointsAccount.setTotalPoints(0);
        // 设置可用积分数量
        pointsAccount.setAvailablePoints(0);
        // 设置创建时间
        pointsAccount.setCreateTime(LocalDateTime.now());
        // 设置更新时间
        pointsAccount.setUpdateTime(LocalDateTime.now());
        // 保存积分账户信息
       boolean save = pointsAccountService.save(pointsAccount);
       if (save && isFirst == 0){
           pointsAccountService.addPoints(id, points, "用户注册活动积分添加", PointsConstant.USER_REGISTER_POINTS);
       }
        // 记录日志：用户注册活动积分添加成功
        log.info("用户注册活动积分添加成功");
    }
}
